package cn.uncode.rpc.core;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import cn.uncode.rpc.exception.FrameworkException;
import cn.uncode.rpc.util.FrameworkUtil;
import cn.uncode.rpc.util.ReflectUtil;


/**
 * AbstractInvoker.
 * 
 */
public abstract class AbstractInvoker<T> extends AbstractNode implements Invoker<T> {

	protected AtomicInteger activeInvokeCount = new AtomicInteger(0);

	protected Class<T>  clazz;

    private volatile boolean destroyed = false;
    
    protected Map<String, Method> methodMap = new HashMap<String, Method>();
    
    public AbstractInvoker(URL url, Class<T> clazz) {
    	super(url);
    	this.clazz = clazz;
        initMethodMap(clazz);
    }
    
    public Response invoke(Request request){
    	if (!isAvailable()) {
            throw new FrameworkException(this.getClass().getSimpleName() + " call Error: node is not available, url=" + url.getUri()
                    + " " + FrameworkUtil.toString(request));
        }

    	activeInvokeCount.incrementAndGet();
        Response response = null;
        try {
            response = doInvoke(request);

            return response;
        } finally {
        	activeInvokeCount.decrementAndGet();
        }
    }
    
    @Override
    public int activeInvokeCount() {
        return activeInvokeCount.get();
    }

    protected void incrActiveCount(Request request) {
    	activeInvokeCount.incrementAndGet();
    }

    protected void decrActiveCount(Request request, Response response) {
    	activeInvokeCount.decrementAndGet();
    }
    
    protected abstract Response doInvoke(Request request);

    public Class<T> getInterface() {
        return clazz;
    }

    public void destroy() {
        if (isDestroyed()) {
            return;
        }
        destroyed = true;
        setAvailable(false);
    }
    
    public boolean isDestroyed() {
        return destroyed;
    }

    public String toString() {
        return getInterface() + " -> " + (getUrl() == null ? "" : getUrl().toString());
    }
    
    
    protected Method lookup(Request request) {
        String methodDesc = ReflectUtil.getMethodDesc(request.getMethodName(), request.getParamtersDesc());

        return methodMap.get(methodDesc);
    }
    
    private void initMethodMap(Class<T> clz) {
        Method[] methods = clz.getMethods();

        for (Method method : methods) {
            String methodDesc = ReflectUtil.getMethodDesc(method);
            methodMap.put(methodDesc, method);
        }
    }
    
    
}